import { LexerToken, LexerTokenType } from "./lexerToken";
import { type ParserNode } from "./parser";

export class PNode implements ParserNode {
  token: LexerToken;
  maxChildren: number;

  children: (string | ParserNode)[] = [];
  constructor(token: LexerToken, maxChildren: number) {
    this.token = token;
    this.maxChildren = maxChildren;
  }

  static genPNodeByToken = (token: LexerToken) => {
    const { type } = token;
    switch (type) {
      case LexerTokenType.ROOT:
        return new PNode(token, 0);
      case LexerTokenType.NUMBER:
        const nNode = new PNode(token, 1);
        nNode.children.push(token.value);
        return nNode;
      case LexerTokenType.OPERATOR:
        return new PNode(token, 2);
      case LexerTokenType.PAR_START:
        return new PNode(token, 0);
      case LexerTokenType.PAR_END:
        return new PNode(token, 0);
      case LexerTokenType.EOF:
        return new PNode(token, 0);
      case LexerTokenType.FUNCTION:
        return new PNode(token, 0);
      case LexerTokenType.DATA:
        const dNode = new PNode(token, 1);
        dNode.children.push(token.value);
        return dNode;
      case LexerTokenType.COMMA:
        return new PNode(token, 0);
      case LexerTokenType.NEGATE:
        return new PNode(token, 1);
      default:
        return new PNode(token, 0);
    }
  };
}

export const isFullNode = (node: ParserNode) => {
  if (isNoChildrenNode(node)) return false;
  return node && node.children && node.children.length >= node.maxChildren;
};

export const isNotFullNode = (node: ParserNode) => {
  if (isNoChildrenNode(node)) return false;
  return node && node.children && node.children.length < node.maxChildren;
};

export const isNoChildrenNode = (node: ParserNode) => {
  return node.maxChildren === 0;
};

export const isConvergenced = (node: ParserNode) => {
  if (!node.token.isConvergenced) return false;
  if (node.children && node.children.length > 0) {
    for (let i = 0; i < node.children.length; i++) {
      const child = node.children[i];
      if (child instanceof PNode && !isConvergenced(child)) return false;
    }
  }
  return true;
};
